use crate::{Callbacks, FillRule, Filler, Polygon};

mod offsetter;
mod polyline;

use offsetter::*;

pub use polyline::Polyline;

#[derive(Clone, Debug)]
pub struct Stroker {
	filler: Filler,
	offset_polygons: Vec<Polygon>,
}
impl Default for Stroker {
	fn default() -> Self {
		Self::new()
	}
}
impl Stroker {
	pub fn new() -> Self {
		Self {
			filler: Filler::new(),
			offset_polygons: Vec::new(),
		}
	}
	pub fn stroke(
		&mut self,
		polylines: &[Polyline],
		StrokerOptions {
			stroke_width,
			join_kind,
			cap_kind,
			miter_limit,
			arc_tolerance,
			fill_rule,
		}: StrokerOptions,
		output_mesh: &mut impl Callbacks,
	) {
		for polyline in polylines {
			self.offset_polygons.push(offset_polyline(
				polyline,
				stroke_width / 2.0,
				OffsetterOptions {
					join_kind,
					cap_kind,
					miter_limit,
					arc_tolerance,
				},
			));
		}
		self.filler.fill(&self.offset_polygons, fill_rule, output_mesh);
	}
}

#[derive(Clone, Copy, Debug, PartialEq)]
pub struct StrokerOptions {
	pub stroke_width: f32,
	pub join_kind: JoinKind,
	pub cap_kind: CapKind,
	pub miter_limit: f32,
	pub arc_tolerance: f32,
	pub fill_rule: FillRule,
}

impl Default for StrokerOptions {
	fn default() -> Self {
		Self {
			stroke_width: 0.05,
			join_kind: JoinKind::default(),
			cap_kind: CapKind::default(),
			miter_limit: 10.0,
			arc_tolerance: 1E-2,
			fill_rule: FillRule::default(),
		}
	}
}

#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)]
pub enum JoinKind {
	Bevel,
	Miter,
	Round,
}
impl Default for JoinKind {
	fn default() -> Self {
		JoinKind::Miter
	}
}

#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)]
pub enum CapKind {
	Butt,
	Square,
	Round,
}
impl Default for CapKind {
	fn default() -> Self {
		CapKind::Butt
	}
}
